package l2

import (
	"reflect"
	"sync"
	"zstackgo/pkg/core/cloudbus"
	"zstackgo/pkg/core/componentloader"
	"zstackgo/pkg/core/db"
	"zstackgo/pkg/core/errorcode"
	"zstackgo/pkg/header/cluster"
	"zstackgo/pkg/header/host"
	"zstackgo/pkg/header/message"
	hl2 "zstackgo/pkg/header/network/l2"
	"zstackgo/pkg/resourceconfig"
	"zstackgo/pkg/tag"
	"zstackgo/spring"
)

var (
	_ L2NetworkManager = new(L2NetworkManagerImpl)
)

func init() {
	o := &L2NetworkManagerImpl{
		l2NetworkFactories:              map[string]hl2.L2NetworkFactory{},
		realizationExts:                 map[*hl2.L2NetworkType]map[*host.HypervisorType]hl2.L2NetworkRealizationExtensionPoint{},
		attachClusterExts:               map[*hl2.L2NetworkType]map[*host.HypervisorType]hl2.L2NetworkAttachClusterExtensionPoint{},
		createExtensions:                []hl2.L2NetworkCreateExtensionPoint{},
		allowedMessageAfterSoftDeletion: map[string]any{},
	}
	o.allowedMessageAfterSoftDeletion["L2NetworkDeletionMsg"] = reflect.TypeOf(hl2.L2NetworkDeletionMsg{})

	spring.Register(o, "L2NetworkManager", []*spring.PluginExtension{
		{
			Interface: "header.Component",
		},
		{
			Interface: "header.Service",
		},
	})
}

type L2NetworkManagerImpl struct {
	bus        cloudbus.CloudBus `autowire:"CloudBusImpl3"`
	dbf        db.DatabaseFacade `autowire:"DatabaseFacadeImpl"`
	tagMgr     tag.TagManager
	pluginRgty componentloader.PluginRegistry `autowire:"PluginRegistryImpl"`
	errf       errorcode.ErrorFacade          `autowire:"ErrorFacadeImpl"`
	rcf        resourceconfig.ResourceConfigFacade

	rwlock                          sync.RWMutex
	l2NetworkFactories              map[string]hl2.L2NetworkFactory
	realizationExts                 map[*hl2.L2NetworkType]map[*host.HypervisorType]hl2.L2NetworkRealizationExtensionPoint
	attachClusterExts               map[*hl2.L2NetworkType]map[*host.HypervisorType]hl2.L2NetworkAttachClusterExtensionPoint
	createExtensions                []hl2.L2NetworkCreateExtensionPoint
	allowedMessageAfterSoftDeletion map[string]any
}

func (impl *L2NetworkManagerImpl) HandleMessage(msg message.Message) {
	if tmp, ok := msg.(message.APIMessage); ok {
		impl.HandleApiMessage(tmp)
	} else {
		impl.HandleLocalMessage(msg)
	}
}

func (impl *L2NetworkManagerImpl) HandleLocalMessage(msg message.Message) {
	if tmp, ok := msg.(hl2.L2NetworkMessage); ok {
		impl.PassThrough(tmp)
	} else {
		impl.bus.DealWithUnknowMessage(msg)
	}
}

func (impl *L2NetworkManagerImpl) HandleApiMessage(msg message.APIMessage) {
	if tmp, ok := msg.(*hl2.APICreateL2NetworkMsg); ok {
		impl.HandleAPICreateL2NetworkMsg(tmp)
	} else if tmp, ok := msg.(*hl2.APIGetL2NetworkTypesMsg); ok {
		impl.HandleAPIGetL2NetworkTypesMsg(tmp)
	} else if tmp, ok := msg.(*hl2.APIGetVSwitchTypesMsg); ok {
		impl.HandleAPIGetVSwitchTypesMsg(tmp)
	} else if tmp, ok := msg.(*hl2.APIGetCandidateL2NetworksForAttachingClusterMsg); ok {
		impl.HandleAPIGetCandidateL2NetworksForAttachingClusterMsg(tmp)
	} else if tmp, ok := msg.(*hl2.APIGetCandidateClustersForAttachingL2NetworkMsg); ok {
		impl.HandleAPIGetCandidateClustersForAttachingL2NetworkMsg(tmp)
	} else if tmp, ok := msg.(hl2.L2NetworkMessage); ok {
		impl.PassThrough(tmp)
	} else {
		impl.bus.DealWithUnknowMessage(msg)
	}
}

func (impl *L2NetworkManagerImpl) HandleAPIGetCandidateClustersForAttachingL2NetworkMsg(msg *hl2.APIGetCandidateClustersForAttachingL2NetworkMsg) {
	reply := hl2.APIGetCandidateClustersForAttachingL2NetworkReply{}
	reply.Inventories = impl.getClusterCandidates(msg)
	impl.bus.Reply(msg, reply)
}

func (impl *L2NetworkManagerImpl) getClusterCandidates(msg *hl2.APIGetCandidateClustersForAttachingL2NetworkMsg) []*cluster.ClusterInventory {

}
